using System;
using System.Collections.Generic;
using System.Text;
using CfgTable;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using NetProtocol.POD;


namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// buff 对象 必须是class，会走事件进行数据修改
    /// </summary>
    public class BuffHandler : IReusableClass
    {
        /// <summary>
        /// ID
        /// </summary>
        public int buffID;

        public CfgBuff config;
        public EBuffAddType addType;

        /// <summary>
        /// buff效果
        /// </summary>
        public List<BuffEffectData> effectives = new List<BuffEffectData>();

        /// <summary>
        /// 发起者
        /// </summary>
        public BuffComponent maker;

        /// <summary>
        /// 持有者
        /// </summary>
        public BuffComponent target;

        /// <summary>
        /// 持续时间
        /// </summary>
        public int timeDuration;

        /// <summary>
        /// 开始时间
        /// </summary>
        public int timeStart;

        /// <summary>
        /// 层数
        /// </summary>
        public int stack { get; private set; }

        /// <summary>
        /// 每层的开始回合数 (开始回合，层数)
        /// </summary>
        public List<(int, int)> stacktimeStart = new List<(int, int)>();

        /// <summary>
        /// 最大堆叠层数
        /// </summary>
        public int maxStack;

        //  Dot参数        
        public int dotFormula;
        public EDamageType dotDamageType = EDamageType.Default;
        public int dotType;
        public EBuffDotTriggerType triggerType;
        /// <summary>
        /// buff组
        /// </summary>
        public int gourp;

        private List<List<BuffEffectContext>> context = new List<List<BuffEffectContext>>();

        public void OnEnable(int nStack)
        {
        }

        public void OnDisable()
        {
            for (int i = 0; i < this.stack; i++)
            {
                for (int j = 0; j < this.effectives.Count; j++)
                {
                    var rEffective = this.effectives[j];
                    var rContext = this.context[i][j];
                    rEffective.effective.DeActive(rContext, rEffective);
                    ClassPool.Put(rContext);
                }
            }

            for (int i = 0; i < this.context.Count; i++)
            {
                ListPool<BuffEffectContext>.Put(this.context[i]);
            }

            this.context.Clear();
            this.effectives.Clear();
        }

        public void OnRefresh(int nRoundNum)
        {
            if (this.timeDuration > 0 && nRoundNum - this.timeStart >= this.timeDuration)
            {
                this.target.Destroy(this);
                return;
            }

            var rResultCtrl = this.maker.unit.battle.playCtrl.resultCtrl;
            var rPOD = BattleUpdateFactory.CreateBuffChange(this, 2, this.target.unit.GUID);
            rResultCtrl.Add(rPOD);

            if (this.addType == EBuffAddType.AddWithTime)
            {
                // remove中会移除最前面的stack时间记录
                for (int i = 0; i < this.stacktimeStart.Count;)
                {
                    var rItem = this.stacktimeStart[i];
                    if (nRoundNum - rItem.Item1 > this.timeDuration)
                    {
                        this.RemoveStack(rItem.Item2);
                    }
                    else
                    {
                        break; // 时间顺序，有不符的后面都不符合
                    }
                }
            }
        }

        public void OnDot(EBuffDotTriggerType rTriggerType)
        {
            if (this.dotFormula > 0 && (rTriggerType == EBuffDotTriggerType.All || rTriggerType == this.triggerType))
            {
                // Dot内置叠层
                BattleUpdatePOD rPOD;
                if (this.dotType == 0)
                {
                    var rDmg = DamageController.TakeDamage(this.maker.unit, this.target.unit, EDamageFrom.Buff, buff: this, damageFormula: this.dotFormula, damageType: this.dotDamageType);
                    rPOD = BattleUpdateFactory.CreateUnitBuffDamage(this.target.unit.GUID, rDmg);
                }
                else
                {
                    var rCure = DamageController.TakeCure(this.maker.unit, this.target.unit, this.dotFormula, 0);
                    rPOD = BattleUpdateFactory.CreateUnitBuffCure(this.target.unit.GUID, rCure);
                }
                var rResultCtrl = this.maker.unit.battle.playCtrl.resultCtrl;
                rResultCtrl.Add(rPOD);
            }
        }


        /// <summary>
        /// 增加层数
        /// </summary>
        public int AddStack(int nStackCount = 1, int param = 0)
        {
            if (this.maxStack <= 0 || this.stack < this.maxStack)
            {
                if (this.maxStack > 0)
                {
                    var nOldStack = this.stack;
                    var nTargetStack =Math.Clamp(this.stack + nStackCount, 0, this.maxStack);
                    nStackCount = nTargetStack - nOldStack;
                }
                for (int j = 0; j < nStackCount; j++)
                {
                    var rContextList = ListPool<BuffEffectContext>.Get();
                    this.context.Add(rContextList);
                    for (int i = 0; i < this.effectives.Count; i++)
                    {
                        var rEffecitve = this.effectives[i];
                        var rContext = ClassPool.Get<BuffEffectContext>();
                        rContext.buff = this;
                        rEffecitve.effective.Active(rContext, rEffecitve, param);
                        rContextList.Add(rContext);
                    }
                }
                this.stack += nStackCount;
                var nRound = this.maker.unit.battle.playCtrl.realRound;
                if (this.addType == EBuffAddType.AddWithTime)
                {
                    this.stacktimeStart.Add((nRound, nStackCount));
                }

                this.timeStart = nRound;
                return nStackCount;
            }
            return 0;
        }

        /// <summary>
        /// 减少层数
        /// </summary>
        public bool RemoveStack(int nStackCount = 1)
        {
            if (this.stack <= nStackCount)
            {
                BuffController.Destroy(this.target, this);
                return false;
            }
            else
            {
                this.stack -= nStackCount;
                for (int i = 0; i < nStackCount; i++)
                {
                    var rContextList = this.context[^1];
                    // 这里加一个检测点，防止出现不一致的情况
                    if (rContextList.Count != this.effectives.Count)
                    {
                        throw new Exception("BuffHandler.RemoveStack: rContextList.Count != rList.Count");
                    }

                    for (int j = 0; j < this.effectives.Count; j++)
                    {
                        var rEffective = this.effectives[j];
                        rEffective.effective.DeActive(rContextList[j], rEffective);
                        ClassPool.Put(rContextList[j]);
                    }

                    ListPool<BuffEffectContext>.Put(rContextList);
                    this.context.RemoveAt(this.context.Count - 1);
                }

                if (this.addType == EBuffAddType.AddWithTime)
                {
                    while (nStackCount > 0 && this.stacktimeStart.Count > 0)
                    {
                        var rItem = this.stacktimeStart[0];
                        if (nStackCount >= rItem.Item2)
                        {
                            this.stacktimeStart.RemoveAt(0);
                            nStackCount -= rItem.Item2;
                        }
                        else
                        {
                            this.stacktimeStart[0] = (rItem.Item1, rItem.Item2 - nStackCount);
                            break;
                        }
                    }
                }
            }

            return true;
        }

#if UNITY_EDITOR
        public override string ToString()
        {
            var rTable = TableCenter.buff.Get(this.buffID);
            var rSb = new StringBuilder();
            rSb.AppendLine($"{rTable.Id}:[{this.stack}],  持续:[{this.target.unit.battle.playCtrl.realRound - this.timeStart}/{this.timeDuration}]");
            rSb.AppendLine("-------------Buff效果-------------");
            for (int i = 0; i < this.effectives.Count; i++)
            {
                rSb.AppendLine($"[{this.effectives[i]}]");
            }

            if (rTable.Dot.Count > 0)
            {
                rSb.AppendLine("-------------Dot效果-------------");
                rSb.AppendLine($"{(this.dotType == 0 ? $"[{(EDamageType)rTable.Dot[1]}]伤害" : "治疗")}公式:[{rTable.Dot[0]}]");
            }

            return rSb.ToString();
        }
#endif


        public uint MaxStore => 20;

        public void OnReset()
        {
            this.maker = null;
            this.target = null;
            this.timeDuration = 0;
            this.timeStart = 0;
            this.stack = 0;
            this.dotFormula = 0;
            this.config = null;
            this.buffID = 0;

            this.stacktimeStart.Clear();
            this.effectives.Clear();
            this.context.Clear();
        }
    }

    public enum EBuffAddType
    {
        Add,
        AddWithTime,
        Replace,
        Exclusive
    }

    public enum EBuffDotTriggerType
    {
        RoundStart,
        RoundEnd,
        TurnStart,
        TurnEnd,
        All,
    }
}